# -*- coding: UTF-8 -*-
# @Create   : 2021/10/8 15:10
# @Author   : yh
# @Remark   : IP设备Server层
import datetime
import logging
import time
from IPy import IP
from typing import List

from mxsoftpy import Server
from mxsoftpy.exception import CError, DataError

from db.common.NetworkManage.IpAM.Ip import IPDB
from model.common.NetworkManage.IpAM.Ip import IPModel, IPUpdateModel, IPSelectModel, IPRetrieveModel
from utils.public.data_process import ip_10_to_2
from utils.public.params_method import update_select_params, paging_data, get_pagination_params


class IPServer(Server):
    __db__ = IPDB

    def create(self, **ip_model):
        """
        新增ip
        :param ip_model: ip模型及ip在数据库所属的位置参数，详情见IP类
        """
        ip_data = IPModel(**ip_model).dict()

        subnet_item = self.db.subnet_items(company=ip_model['company'], network=ip_model['network'],
                                           subnet=ip_model['subnet'])
        subnet_mask = ip_10_to_2(subnet_item['SubnetMask'])
        if eval('0b' + ip_10_to_2(ip_model['ip'])) & eval('0b' + subnet_mask) != eval(
                '0b' + ip_10_to_2(subnet_item['SubnetIp'])) & eval('0b' + subnet_mask):
            raise Exception('新增ip失败，此ip不属于该子网')

        return self.db.create(company=ip_model['company'], network=ip_model['network'], **ip_data)

    def delete(self, **delete_data):
        """
        删除ip
        :param delete_data: 包含要删除的ip，多个ip使用逗号分隔
        """
        return self.db.delete(**delete_data)

    def retrieve(self, **retrieve_query) -> dict:
        """
        获取ip详情
        :param retrieve_query: 查询参数 ip、network、company
        """
        res = self.db.retrieve(ip=retrieve_query['ip'], network=retrieve_query['network'],
                               company=retrieve_query['company'])
        return IPRetrieveModel(**res).dict()

    def update(self, **update_data):
        """
        更新ip
        """
        ip_data = IPUpdateModel(**update_data).dict()
        return self.db.update(company=update_data['company'], network=update_data['network'], ip=update_data['ip'],
                              **ip_data)

    @staticmethod
    def __check_state(ip: dict) -> int:
        """
        当日期格式化错误或取不到日期时：默认状态为0：未使用
        """
        if ip.get('active') == 1:
            state = 1
        else:
            day_30 = datetime.datetime.now() - datetime.timedelta(days=30)
            if ip.get('time'):
                # try:
                state = 2 if datetime.datetime.fromtimestamp(
                    time.mktime(time.strptime(ip['time'], "%Y-%m-%d %H:%M:%S"))) > day_30 else 3
                # except ValueError:
                #     state = 0
            else:
                state = 0
        return state

    def select(self, company: str, **query):
        """
        条件查询ip
        :param company: 所属公司
        :param query: 查询条件及分页条件
        """
        from bsmiddle import GetIPJson
        try:
            res = eval(GetIPJson(company, query['network'], query['subnet']))  # 从缓存获取指定公司、网络、子网下的ip
        except TypeError as e:
            logging.error('使用bsmiddle模块中的GetIPJson从缓存获取数据时，获取的数据无法使用eval序列化成字典，错误详情：%s' % str(e))
            raise CError('查询失败')

        # 增加排序 编辑IP会产生乱序 zyl
        data_new = sorted(res['data'], key=lambda x: int(x['ip'].split('.')[-1]))
        res_data = []
        query_data = update_select_params(IPSelectModel(**query).dict())
        if query_data and res.get('data'):  # 判断是否有查询条件

            for ip in data_new:
                flag = True  # 条件标志，当循环判断的条件有一个不满足时，标记改为False，即不满足
                ip['state'] = self.__check_state(ip)  # 根据条件判断当前ip状态

                for k, v in query_data.items():
                    if str(ip[k]).find(str(v)) == -1:
                        flag = False
                if flag:
                    res_data.append(ip)
        elif res.get('data'):
            for ip in data_new:
                ip['state'] = self.__check_state(ip)  # 根据条件判断当前ip状态
                res_data.append(ip)

        return paging_data(res_data, **get_pagination_params(query))

    def trust(self, **trust_data) -> List[str]:
        """
        添加ip信任
        :param trust_data: company、network、trusts(要添加信任的ip列表，多个ip使用逗号分隔)
        """
        return self.db.trust(company=trust_data['company'], network=trust_data['network'], trusts=trust_data['trusts'])

    def list(self, **query):
        """
        列表展示ip设备
        """
        from bsmiddle import GetIPJson

        try:
            subnet_data = eval(GetIPJson(query['company'], query['network'], query['subnet']))  # 从缓存获取指定公司、网络、子网下的ip
        except TypeError as e:
            logging.error('使用bsmiddle模块中的GetIPJson从缓存获取数据时，获取的数据无法使用eval序列化成字典，错误详情：%s' % str(e))
            raise CError('查询失败')
        except NameError:
            return []  # 解析失败直接返回空

        res = dict()
        res['data'] = list()
        res['total'] = {0: 0, 1: 0, 2: 0, 3: 0}  # 统计ip的所有状态（0 未使用、1 已使用、2 30天内使用、3 30天前使用）
        ip_dict = dict()
        for i in subnet_data['data']:
            i['state'] = self.__check_state(i)
            ip_dict[i['ip']] = i

        try:
            ip_cls = IP(subnet_data['Ip']).make_net(subnet_data['Mask'])
            for ip in ip_cls:
                state = ip_dict[str(ip)]['state'] if ip_dict.get(str(ip)) else 0
                res['total'][state] += 1
                res['data'].append({
                    'id': str(ip).rsplit('.', 1)[1],  # 以二进制ip地址最后八位转为十进制的数字作为id

                    # 状态 （0 未使用、1 已使用、2 30天内使用、3 30天前使用）
                    'state': state,
                    'ip': str(ip)
                })
        except ValueError as e:
            logging.error(
                '无法将子网ip和子网掩码转换为IP类，子网ip：%s，子网掩码：%s，错误详情：%s' % (subnet_data['Ip'], subnet_data['Mask'], str(e)))
            raise DataError('获取数据失败')
        except KeyError as e:
            logging.error('从GetIPJson方法获取IP数据的时候，无法获取键：%s' % str(e))
            raise CError('获取数据失败')

        return res
